
const fs = require('fs/promises');
fs.mkdirp = (folderPath) => {
    return require('mkdirp')(folderPath);
}

const path = require('path');

if (typeof String.prototype.replaceAll === "undefined") {
	
	const stringReplaceAll = (string, match, replacer) => {
		let index = string.indexOf(match);
		if (index === -1) {
			return string;
		}

		let newStr = string.replace(match, replacer);
		return stringReplaceAll(newStr, match, replacer);
	};
	
    String.prototype.replaceAll = function(match, replace) {
       return stringReplaceAll(this, match, replace).toString();
    }
}

const sleep = (time) => {
    return new Promise(resolve => {
        setTimeout(resolve, time);
    });
}

const checkFileExists = async (filePath) => {
    try {
        await fs.access(filePath, fs.constants.F_OK);
        return true
    } catch {
        return false
    }
}

const lookUpDir = (folder, ignores, mapFunc) => {
    if (typeof ignores === 'function') {
        mapFunc = ignores;
        ignores = undefined;
    }
    ignores = ignores || [ '.git', '.svn', 'tmp', 'temp' ];
    return new Promise(async (resolve) => {
        let files = await fs.readdir(folder);
        for (let file of files) {
            if (ignores && ignores.length > 0 && ignores.indexOf(file) >= 0) continue;
            let stop = await mapFunc(file, path.resolve(folder, file));
            if (stop === true) {
                resolve(true);
                return;
            }
        }
        resolve();
    });
}

const deepLookUpDir = async (folder, ignores, mapFunc) => {
    if (typeof ignores === 'function') {
        mapFunc = ignores;
        ignores = undefined;
    }

    if (folder instanceof Array) {
        for (let targetFolder of folder) {
            let stop1 = await lookUpDir(targetFolder, ignores, async (file, filePath) => {
                let stop2 = undefined;
                let fstat = await fs.lstat(filePath);
                if (fstat.isDirectory()) {
                    stop2 = await deepLookUpDir(filePath, ignores, mapFunc);
                    if (stop2) return true;
                }
                stop2 = await mapFunc(file, filePath);
                if (stop2) return true;
            });
            if (stop1) return;
        }
    } else {
        await lookUpDir(folder, ignores, async (file, filePath) => {
            let stop = undefined;
            let fstat = await fs.lstat(filePath);
            if (fstat.isDirectory()) {
                stop = await deepLookUpDir(filePath, ignores, mapFunc);
                if (stop) return true;
            }
            stop = await mapFunc(file, filePath);
            if (stop) return true;
        });
    }
}

const load = (url) => {
    let file = fs.readFile(path.resolve(__dirname, './files/' + url), 'utf-8');
    return file;
}

const loadFile = (url) => {
    return load(url);
}

const loadJSON = async (url) => {
    let file = await load(url);
    return JSON.parse(file);
}

const camelCaseToUnderline = (name) => {
    let len = name.length;
    let newName = '';
    for (let i = 0; i < len; i++) {
        let char = name.charAt(i);
        if (char.toUpperCase() === char) {
            char = char.toLowerCase();
            if (i > 0) {
                let prevChar = name.charAt(i - 1);
                if (prevChar.toLowerCase() === prevChar) {
                    char = '_' + char;
                } else {
                    if (i < len - 1) {
                        let nextChar = name.charAt(i + 1);
                        if (nextChar.toLowerCase() === nextChar) {
                            char = '_' + char;
                        }
                    }
                }
            }
        }
        newName += char;
    }
    return newName;
}

const lineToCamelCase = (name, firstCharUpper) => {
    let len = name.length;
    let newName = '';
    let needUpper = false;
    for (let i = 0; i < len; i++) {
        let char = name.charAt(i);
        if (char === '_' || char === '-') {
            char = '';
            needUpper = true;
        } else if (needUpper) {
            needUpper = false;
            char = char.toUpperCase();
        }
        if (i === 0 && firstCharUpper) {
            char = char.toUpperCase();
        }
        newName += char;
    }
    return newName;
}

const randomString = (len) => {
    const allCapsAlpha = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"];
    const allLowerAlpha = [..."abcdefghijklmnopqrstuvwxyz"];
    const allUniqueChars = [..."~!@%^&*()_+-=<>?"];
    const allNumbers = [..."0123456789"];

    const base = [...allCapsAlpha, ...allNumbers, ...allLowerAlpha, ...allUniqueChars];

    return [...Array(len)]
        .map(i => base[Math.random() * base.length | 0])
        .join('');
}

module.exports = {
    sleep,
    checkFileExists,
    lookUpDir,
    deepLookUpDir,
    loadFile,
    loadJSON,
    camelCaseToUnderline,
    lineToCamelCase,
    randomString,
}